﻿using System;
using System.Collections.Generic;
using System.Linq;
using GCTrackableRace.Interfaces;
using GcTrackableRace.Entities;
using GcTrackableRace.ScoreCalculator.Helpers;

namespace GcTrackableRace.ScoreCalculator.Rules
{
	public class TotalDistanceInKilometresRule: BaseRule, IRaceRule
	{
		public TotalDistanceInKilometresRule(string reportColumnName, string startDate, string endDate, string pointAllocation)
			:base(reportColumnName, startDate, endDate, pointAllocation)
		{}
  
		protected override void SetRuleName()
		{
			RuleName = "Total distance in kilometers rule";
		}

		public override void Process(ITrackable trackable, IEnumerable<ITrackableLog> trackableLogs)
		{
			var droppedLogs = (
				from log in trackableLogs
				where (
					(log.LogType == LogType.DroppedOff || log.LogType == LogType.Visited)
					&&
						(
							log.Date >= StartDate
							&&
							log.Date <= EndDate
						)
					)
				select log)
				.OrderBy(logs => logs.Date)
				.ThenBy(logs => logs.LogId)
				.ToList();

			double totalDistance = 0;

			double prevLat = 0;
			double prevLon = 0;

			foreach (var log in droppedLogs)
			{
				if (prevLat == 0)
				{
					prevLat = Double.Parse(log.Latitude.ToString());
					prevLon = Double.Parse(log.Longitude.ToString());
				}
				else
				{
					var lat = Double.Parse(log.Latitude.ToString());
					var lon = Double.Parse(log.Longitude.ToString());

					var distance = Haversine.InKilometers(
						prevLat, prevLon,
						lat, lon
					);

					totalDistance += distance;

					prevLat = lat;
					prevLon = lon;
				}
			}

			trackable.AddScore(new RuleScore(
				RuleName, 
				ReportColumnName,
				(int)totalDistance,
				(int)((decimal)totalDistance * PointAllocation),
				totalDistance.ToString())
			);
		}
	}
}